package cc.shacocloud.kotlin.tools.uitls

/**
 * 修复路径
 *
 * 如果原路径尾部有分隔符，则保留为标准分隔符（/），否则不保留
 *
 *  1. 1. 统一用 /
 *  1. 2. 多个 / 转换为一个 /
 *  1. 3. 去除左边空格
 *  1. 4. .. 和 . 转换为绝对路径，当..多于已有路径时，直接返回根路径
 *
 * 例子：
 * ```
 * "/foo//" =》 "/foo/"
 * "/foo/./" =》 "/foo/"
 * "/foo/../bar" =》 "/bar"
 * "/foo/../bar/" =》 "/bar/"
 * "/foo/../bar/../baz" =》 "/baz"
 * "/../" =》 "/"
 * "foo/bar/.." =》 "foo"
 * "foo/../bar" =》 "bar"
 * "foo/../../bar" =》 "bar"
 * "//server/foo/../bar" =》 "/server/bar"
 * "//server/../bar" =》 "/bar"
 * "C:\\foo\\..\\bar" =》 "C:/bar"
 * "C:\\..\\bar" =》 "C:/bar"
 * "~/foo/../bar/" =》 "~/bar/"
 * "~/../bar" =》 普通用户运行是'bar的home目录'，ROOT用户运行是'/bar'
 * ```
 * @param path 原路径
 * @return 修复后的路径
 */
fun String.pathNormalize(): String {
    var pathToUse = this

    // 识别home目录形式，并转换为绝对路径
    if (pathToUse.startsWith('~')) {
        pathToUse = System.getProperty("user.home") + pathToUse.substring(1)
    }

    // 统一使用斜杠
    pathToUse = pathToUse.replace("[/\\\\]+".toRegex(), "/")
    // 去除开头空白符，末尾空白符合法，不去除
    pathToUse = pathToUse.trimStart()
    //兼容Windows下的共享目录路径（原始路径如果以\\开头，则保留这种路径）
    if (startsWith("\\\\")) {
        pathToUse = "\\" + pathToUse
    }

    var prefix = ""
    val prefixIndex: Int = pathToUse.indexOf(":")
    if (prefixIndex > -1) {
        // 可能Windows风格路径
        prefix = pathToUse.substring(0, prefixIndex + 1)
        if (prefix.startsWith('/')) {
            // 去除类似于/C:这类路径开头的斜杠
            prefix = prefix.substring(1)
        }
        if (!prefix.contains("/")) {
            pathToUse = pathToUse.substring(prefixIndex + 1)
        } else {
            // 如果前缀中包含/,说明非Windows风格path
            prefix = ""
        }
    }
    if (pathToUse.startsWith("/")) {
        prefix += "/"
        pathToUse = pathToUse.substring(1)
    }

    val pathList = pathToUse.split('/')

    val pathElements = mutableListOf<String>()
    var tops = 0
    var element: String
    for (i in pathList.indices.reversed()) {
        element = pathList[i]
        // 只处理非.的目录，即只处理非当前目录
        if ("." != element) {
            if (".." == element) {
                tops++
            } else {
                if (tops > 0) {
                    // 有上级目录标记时按照个数依次跳过
                    tops--
                } else {
                    // 找到普通路径元素
                    pathElements.add(0, element)
                }
            }
        }
    }

    if (tops > 0 && prefix.isEmpty()) {
        // 只有相对路径补充开头的..，绝对路径直接忽略之
        while (tops-- > 0) {
            //遍历完节点发现还有上级标注（即开头有一个或多个..），补充之
            pathElements.add(0, "..")
        }
    }

    return prefix + pathElements.joinToString("/")
}

